<?php
/**
 * Filter to turn xml reference data into xhtml
 * Links to local/references library so user can re-use reference data
 *
 * @copyright &copy; 2009 The Open University
 * @author j.platts@open.ac.uk
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
 * @package filter/references
 */

function references_filter ($courseid, $text) {
    global $CFG, $COURSE;

    //Check for reference xml in string
    if(empty($text)){
        return $text;
    }

    if(strpos($text,'&lt;references&gt;')===false && strpos($text,'&amp;lt;references&amp;gt;')===false && strpos($text,'<references>')===false){
        //no references tag detected so return
        return $text;
    }
    
    //Only require libs when we are sure we need them.
    require_once($CFG->libdir . '/ajax/ajaxlib.php');

    include_once(dirname(__FILE__).'/export_references.php');

    references_filter_globals::$counter++;

    if(references_filter_globals::$counter==1){
        if(ajaxenabled() || class_exists('ouflags')){
            //"get"
            require_js(array('yui_yahoo','yui_yuiloader','yui_dom-event','yui_dragdrop','yui_container','yui_element','yui_button','yui_connection'));
            require_js($CFG->wwwroot.'/filter/references/references_filter.js.php');
        }
    }
    
    //create a semi-random num to identify this filter session (for ids in html)
    references_filter_globals::$randnum = rand(1,20);

    //Work out if <references> tag(s) are in $text, account for html entities (<=&lt;)
    //get just the xml (can't use regex as this keep falling over on big strings!)
    if(strpos($text,'&amp;lt;references&amp;gt;')!==false){
        $text = htmlspecialchars_decode($text);
    }
    
    if(strpos($text,'&lt;references&gt;')!==false){
        $textarr = explode('&lt;references&gt;',$text);
        //go thru array and if el has references closing tag then get string from start to this
        for($a=0,$max=count($textarr);$a<$max;$a++){
            $textstr = $textarr[$a];
            $endtagpos = strpos($textstr,'&lt;/references&gt;');
            if($endtagpos!==false){
                $textstr = substr($textstr,0,$endtagpos);
                $textstr = strip_tags($textstr);//We have to strip tags here as moodle tries to make URLs into <a> tags etc when using format_text
                //convert < and > from htm ents
                $textstr = str_replace('&lt;','<',$textstr);
                $textstr = str_replace('&gt;','>',$textstr);
                $textstr = str_replace('&quot;','"',$textstr);
                //add references tag
                $textstr = '<references>'.$textstr.'</references>';
                //send to function to get replacement text
                $reptext = references_filter_replace($textstr, $a);
                //replace the text in el with replacement
                $textarr[$a] = $reptext.substr($textarr[$a],$endtagpos+19);
            }
        }
        //replace text with updated ver
        $text = implode('',$textarr);
    }
    if(strpos($text,'<references>')!==false){
        $textarr = explode('<references>',$text);
        //go thru array and if el has references closing tag then get string from start to this
        for($a=0,$max=count($textarr);$a<$max;$a++){
            $textstr = $textarr[$a];
            $endtagpos = strpos($textstr,'</references>');
            if($endtagpos!==false){
                $textstr = substr($textstr,0,$endtagpos);
                //add references tag
                $textstr = '<references>'.$textstr.'</references>';
                //send to function to get replacement text
                $reptext = references_filter_replace($textstr, $a);
                //replace the text in el with replacement
                $textarr[$a] = $reptext.substr($textarr[$a],$endtagpos+13);
            }
        }
        $text = implode('',$textarr);
    }
    return $text;
}
/**
 * Returns replacement text for the text string sent
 * @param $textstr string: references xml string
 * @return string
 */
function references_filter_replace($textstr, $counter){
    global $CFG, $COURSE;
    //remove br and returns added by html editor (use str_replace as quicker than regex)
    $textstr = str_ireplace('<br />','',$textstr);
    $textstr = str_ireplace('<br/>','',$textstr);
    $textstr = str_replace("\n",'',$textstr);

    //convert to xml
    $doc = new DOMDocument('1.0','utf-8');
    $doc->preserveWhiteSpace = false;
    $doc->formatOutput = false;
    //custom handler to trap any messed-up xml (so no fatal error)
    try{
        set_error_handler("references_HandleXmlError");
        $doc->loadXML($textstr);
        restore_error_handler();
    }
    catch(DOMException $error){
        return '';//return nothing if error
    }

    $referencetags = $doc->getElementsByTagName('reference');

    //If there is a linking library send data to that to get array of links
    //if (class_exists('linking')) {
    if (file_exists(dirname(__FILE__).'/../../local/references/linking.php')) {
        @include_once(dirname(__FILE__).'/../../local/references/linking.php');

        $linksarray = linking::create_link($doc);
        //add links to xml <reference link=""
        for($a=0,$max=$referencetags->length;$a<$max;$a++){
            if(isset($linksarray[$a]) && $linksarray[$a]!=null){
                $linkatt = $doc->createAttribute('link');
                $linkatt->nodeValue = htmlentities($linksarray[$a]);
                $referencetags->item($a)->appendChild($linkatt);
            }
        }
    }

    if (file_exists(dirname(__FILE__).'/../../local/references/export.php')) {
        //add in info that will be used to create an export menu for each ref (only creates this if export lib file available)
        //get info from references_filter_export
        $exportlist = references_filter_export::get_formats();
        //create nodes in $doc <menu><export><opt name title desc ajax/></export><download><opt...
        $menunode=$doc->createElement('menu');
        $exportnode=$doc->createElement('export');
        $downnode=$doc->createElement('download');
        for($a=0,$max=count($exportlist);$a<$max;$a++){
            $curformat=&$exportlist[$a];
            //create opt node with atts
            $optnode = $doc->createElement('opt');
            $att = $doc->createAttribute('name');
            $att->nodeValue = $curformat['name'];
            $optnode->appendChild($att);
            //title (display name)
            $att = $doc->createAttribute('title');
            $att->nodeValue = strip_tags($curformat['disname']);
            $optnode->appendChild($att);
            //description
            $att = $doc->createAttribute('desc');
            $att->nodeValue = strip_tags($curformat['description']);
            $optnode->appendChild($att);
            //ajax off on this export?
            $ajaxval = 1;
            if(isset($curformat['noajax']) || $curformat['type']==references_filter_export::DOWNLOAD){
                $ajaxval = 0;
            }
            $att = $doc->createAttribute('ajax');
            $att->nodeValue = $ajaxval;
            $optnode->appendChild($att);

            //add to correct node
            if($curformat['type']==references_filter_export::DOWNLOAD){
                $downnode->appendChild($optnode);
            }else if($curformat['type']==references_filter_export::EXPORT){
                $exportnode->appendChild($optnode);
            }

        }
        $menunode->appendChild($exportnode);
        $menunode->appendChild($downnode);
        $doc->appendChild($menunode);
    }

    //Transform our refxml data into (x)html using xslt
    // Load XSL template
    $xsl = new DOMDocument();
    if(!$xsl->load(dirname(__FILE__).'/xml2html.xsl')){
        return '';
    }

    // Create new XSLTProcessor
    $xslt = new XSLTProcessor();
    // Load stylesheet
    if(!$xslt->importStylesheet($xsl)){
        return '';
    }

    //Number param so all html id on page are unique
    //$xslt->setParameter('','num',references_filter_globals::$counter);//number of times called filter
    //Number is set to a random number to ensure is always unique (only one )
    $xslt->setParameter('','num',references_filter_globals::$randnum);
    $xslt->setParameter('','count',$counter);//number of references tag in this call
    $xslt->setParameter('','sesskey',sesskey());
    //page references will be submitted to on export
    $xslt->setParameter('','postto',$CFG->wwwroot.'/filter/references/export_references.php');
    $xslt->setParameter('','downloadhead',get_string('refexport_downloadto','references'));
    $xslt->setParameter('','exporthead',get_string('refexport_exportto','references'));
    $xslt->setParameter('','exportbutname',get_string('exportbutname','filter_references'));
    $xslt->setParameter('','seltitle',get_string('seltitle','filter_references'));
    //image for submit button
    $xslt->setParameter('','imageloc',$CFG->wwwroot.'/local/references/images/export_16.png');
    //Send info to the export about what course we came from
    $xslt->setParameter('','courseid',$COURSE->id);
    $xslt->setParameter('','coursename',$COURSE->shortname);
    if(class_exists('ouflags')){
        $xslt->setParameter('','ajaxenabled',true);
    }else{
        $xslt->setParameter('','ajaxenabled',ajaxenabled());
    }
    $xslt->setParameter('','noajax',get_string('noajax','filter_references',$CFG->wwwroot.'/filter/references/export_references.php?button=null&amp;info='.sesskey().'~~'.$COURSE->shortname.'~~'.$COURSE->id));
    $xslt->setParameter('','noajax2',get_string('noajax2','filter_references'));
    $xslt->registerPHPFunctions();
    
    $results = $xslt->transformToDoc(&$doc);

    //remove doctype
    $result = preg_replace('/<!DOCTYPE[^>]*>/',' ',$results->saveXML());
    $result = str_replace('<?xml version="1.0" encoding="utf-8"?>','',$result);
    $result = preg_replace('/\s\s/','',$result);
    $result = str_replace('xmlns:php="http://php.net/xsl"','',$result);
    //remove other junk from doc
    //$result = str_replace('&nbsp;&nbsp;&nbsp;','',$result);
    $result = str_replace("\t",'',$result);
    return $result;
}


function references_HandleXmlError($errno, $errstr, $errfile, $errline){
    if ($errno==E_WARNING && (substr_count($errstr,"DOMDocument::loadXML()")>0))
    {
        throw new DOMException(get_string('reference_xmlloaderror','references'));
    }else{
        return false;
    }
}

//Global static class, used to store vars across multiple calls on a page
class references_filter_globals{
    public static $counter = 0;//number of times used
    public static $randnum = 0;
}
?>